package com.ysx.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ysx.article.dto.ApArticleDto;
import com.ysx.article.dto.ArticleBehaviourDtoQuery;
import com.ysx.article.mapper.ApArticleConfigMapper;
import com.ysx.article.mapper.ApArticleContentMapper;
import com.ysx.article.mapper.ApArticleMapper;
import com.ysx.article.pojo.*;
import com.ysx.article.service.ApArticleService;
import com.ysx.article.service.ApAuthorService;
import com.ysx.article.service.ApCollectionService;
import com.ysx.behaviour.feign.ApBehaviorEntryFeign;
import com.ysx.behaviour.feign.ApLikesBehaviorFeign;
import com.ysx.behaviour.feign.ApUnlikesBehaviorFeign;
import com.ysx.behaviour.pojo.ApBehaviorEntry;
import com.ysx.behaviour.pojo.ApLikesBehavior;
import com.ysx.behaviour.pojo.ApUnlikesBehavior;
import com.ysx.common.constants.BusinessConstants;
import com.ysx.common.constants.SystemConstants;
import com.ysx.common.pojo.PageInfo;
import com.ysx.common.pojo.PageRequestDto;
import com.ysx.common.utils.RequestHeaderInfoUtils;
import com.ysx.user.feign.ApUserFollowFeign;
import com.ysx.user.pojo.ApUserFollow;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 文章信息表，存储已发布的文章 服务实现类
 * </p>
 *
 * @author ljh
 * @since 2021-09-08
 */
@Service
public class ApArticleServiceImpl extends ServiceImpl<ApArticleMapper, ApArticle> implements ApArticleService {
    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private ApArticleContentMapper apArticleContentMapper;

    @Autowired
    private ApArticleConfigMapper apArticleConfigMapper;

    @Autowired
    private ApBehaviorEntryFeign apBehaviorEntryFeign;//查询是否存在行为实体

    @Autowired
    private ApUnlikesBehaviorFeign apUnlikesBehaviorFeign;//查询是否不喜欢过这篇文章

    @Autowired
    private ApLikesBehaviorFeign apLikesBehaviorFeign;//查询是否点赞

    @Autowired
    private ApUserFollowFeign apUserFollowFeign;//查询用户和作者之间的关注状态

    @Autowired
    private ApAuthorService apAuthorService;//查询作者

    @Autowired
    private ApCollectionService apCollectionService;//查询是否收藏

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //有条件的 分页 排序查
    @Override
    public PageInfo<ApArticle> pageByOrder(PageRequestDto<ApArticle> pageRequestDto) {
        Long page = pageRequestDto.getPage();
        Long size = pageRequestDto.getSize();
        ApArticle body = pageRequestDto.getBody();
        //如果为空 则创建 并赋值为0 标识查询所有频道列表信息
        if(body!=null && body.getChannelId()!=null){

        }else{
            body = new ApArticle();
            //查询所有频道
            body.setChannelId(0);
        }
        Long start = (page-1)*size;
        List<ApArticle> apArticleList = apArticleMapper.pageByOrder(start,size,body.getChannelId());
        Long total = apArticleMapper.selectArticleCount(body.getChannelId());
        Long totalPages = total/size;
        if(total%size>0){
            totalPages++;
        }
        return new PageInfo<ApArticle>(page,size,total,totalPages,apArticleList);
    }

    //展示详细的文章数据
    @Override
    public ApArticleDto detailByArticleId(Long articleId) {
        //1.根据articleId 获取文章详情内容
        QueryWrapper<ApArticleContent> queryWrapper1 = new QueryWrapper();
        queryWrapper1.eq("article_id",articleId);

        ApArticleContent articleContent = apArticleContentMapper.selectOne(queryWrapper1);
        //2.获取articleId 获取文章配置信息
        QueryWrapper<ApArticleConfig> queryWrapper2 = new QueryWrapper();
        queryWrapper2.eq("article_id",articleId);
        queryWrapper2.eq("is_down",0);
        queryWrapper2.eq("is_delete",0);
        ApArticleConfig apArticleConfig = apArticleConfigMapper.selectOne(queryWrapper2);
        //3.合并返回
        ApArticleDto articleInfoDto = new ApArticleDto();
        articleInfoDto.setApArticleContent(articleContent);
        articleInfoDto.setApArticleConfig(apArticleConfig);
        return articleInfoDto;
    }

    //展示文章中的用户行为信息
    @Override
    public Map<String, Object> loadArticleBehaviour(ArticleBehaviourDtoQuery articleBehaviourDtoQuery) {
        //1.定义变量
        //是否喜欢 默认是false
        boolean isunlike = false;
        //是否点赞 默认是false
        boolean islike = false;
        //是否收藏
        boolean isCollection = false;
        //是否关注
        boolean isFollow = false;
        Map<String, Object> resultMap = new HashMap<String, Object>();
        //{"isfollow":true,"islike":true,"isunlike":false,"iscollection":true}
        resultMap.put("isfollow", isFollow);
        resultMap.put("islike", islike);
        resultMap.put("isunlike", isunlike);
        resultMap.put("iscollection", isCollection);

        String userId = RequestHeaderInfoUtils.getHeaderUserId();
        ApBehaviorEntry entry = null;
        if (userId.equals("0")) {
            //2.如果是匿名用户 则点赞的是设备
            entry = apBehaviorEntryFeign.findByUserIdOrEquipmentId(articleBehaviourDtoQuery.getEquipmentId(), SystemConstants.TYPE_E);
        } else {
            //3.如果是真实的用户 则点赞的是用户
            entry = apBehaviorEntryFeign.findByUserIdOrEquipmentId(Integer.valueOf(userId), SystemConstants.TYPE_USER);
        }
        if (entry == null) {
            return resultMap;
        }

        //3.查询是否关注  查询是否喜欢  查询是否收藏 查询是否点赞
        //3.1 通过feign调用查询 是否喜欢
        ApUnlikesBehavior unlikesBehavior = apUnlikesBehaviorFeign.getUnlikesBehavior(articleBehaviourDtoQuery.getArticleId(), entry.getId());
        if (unlikesBehavior != null && "1".equals(unlikesBehavior.getType().toString())) {
            isunlike = true;
            resultMap.put("isunlike", isunlike);
        }

        //查询是否点赞
        ApLikesBehavior likesBehavior = apLikesBehaviorFeign.getLikesBehavior(articleBehaviourDtoQuery.getArticleId(), entry.getId());
        if (likesBehavior != null && "1".equals(likesBehavior.getOperation().toString())) {
            islike = true;
            resultMap.put("islike", islike);
        }


        //先查询作者
        ApAuthor apAuthor = apAuthorService.getById(articleBehaviourDtoQuery.getAuthorId());
        Integer followId = apAuthor.getUserId();

        //查询是否关注
        ApUserFollow apUserFollow = apUserFollowFeign.getApUserFollow(followId, Integer.parseInt(userId));
        if (null != apUserFollow) {
            isFollow = true;
            resultMap.put("isfollow", isFollow);
        }

        //查询是否收藏 （由于收藏表在文章的微服务 故可以直接调用）
        QueryWrapper<ApCollection> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("entry_id", entry.getId());
        queryWrapper.eq("article_id", articleBehaviourDtoQuery.getArticleId());
        queryWrapper.eq("type", 0);//点赞目标 文章0 动态1
        ApCollection apCollection = apCollectionService.getOne(queryWrapper);
        if (apCollection != null) {
            isCollection = true;
            resultMap.put("iscollection", isCollection);
        }

        //返回最终结果
        return resultMap;
    }


    /**
     * 计算文章分值保存到Redis中
     */
    @Override
    public void saveToRedis() {
        // 查询发布时间为出前 5天的热门文章数据 计算分值
        QueryWrapper<ApArticle> queryWrapper = new QueryWrapper<ApArticle>();
        //now>=push>=now-5
        LocalDateTime end = LocalDateTime.now();
        LocalDateTime start = end.minusDays(5);
        queryWrapper.between("publish_time", start, end);
        List<ApArticle> apArticleList = apArticleMapper.selectList(queryWrapper);


        //2. 计算分数值(公式)
        if(apArticleList!=null ){
            for (ApArticle apArticle : apArticleList) {
                // 排名所有频道的
                stringRedisTemplate.boundZSetOps(
                        BusinessConstants.ArticleConstants.HOT_ARTICLE_FIRST_PAGE
                                +BusinessConstants.ArticleConstants.DEFAULT_TAG)
                        .add(JSON.toJSONString(apArticle),Double.valueOf(computeScore(apArticle)));
                // 根据频道进行排名 key: 就是频道ID
                stringRedisTemplate.boundZSetOps(
                        BusinessConstants.ArticleConstants.HOT_ARTICLE_FIRST_PAGE
                                +apArticle.getChannelId()).add(JSON.toJSONString(apArticle),
                        Double.valueOf(computeScore(apArticle)));

            }
        }


    }



    //计算分值
    @Override
    public Integer computeScore(ApArticle apArticle) {
        Integer score=0;
        if(apArticle!=null){
            //点赞
            if(apArticle.getLikes()!=null){
                score+=apArticle.getLikes()*BusinessConstants.ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
            }

            //收藏
            if(apArticle.getCollection()!=null){
                score+=apArticle.getCollection()*BusinessConstants.ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
            }

            //评论
            if(apArticle.getComment()!=null){
                score+=apArticle.getComment()*BusinessConstants.ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
            }
            //阅读数  1分
            if(apArticle.getViews()!=null){
                score+=apArticle.getViews()*1;//youhua
            }

        }
        return score;
    }


    /**
     * 这样，当页面需要展示热门数据的时候，前端直接调用该接口即可，返回一个列表，前端自己通过数据展示判断，
     * 当数据展示完毕以后，需要加载更多，则调用另外一个接口进行分页查询，此时数据从数据库获取即可。
     * @param channelId
     * @return
     */
    @Override
    public List<ApArticle> loadMoreFromRedis(Integer channelId) {

        //只获取30个
        Set<String> range = stringRedisTemplate
                .boundZSetOps(BusinessConstants.ArticleConstants.HOT_ARTICLE_FIRST_PAGE + channelId)
                .reverseRange(0, 30);
        if(range!=null && range.size()>0) {
            List<ApArticle> collect = range.stream().map(s -> JSON.parseObject(s, ApArticle.class)).collect(Collectors.toList());
            return collect;
        }
        return null;
    }

}
